/// *
// * Copyright 2010-2012 VMware and contributors
// *
// * Licensed under the Apache License, Version 2.0 (the "License");
// * you may not use this file except in compliance with the License.
// * You may obtain a copy of the License at
// *
// * http://www.apache.org/licenses/LICENSE-2.0
// *
// * Unless required by applicable law or agreed to in writing, software
// * distributed under the License is distributed on an "AS IS" BASIS,
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// * See the License for the specific language governing permissions and
// * limitations under the License.
// */
//
// package cn.wenhao.javaClassReload.classVisitors;
//
// import org.objectweb.asm.Label;
// import org.objectweb.asm.MethodVisitor;
// import org.objectweb.asm.Opcodes;
//
// import cn.wenhao.javaClassReload.javaClassElements.FieldMember;
// import cn.wenhao.javaClassReload.javaClassElements.MethodMember;
// import cn.wenhao.javaClassReload.utils.Utils;
// import cn.wenhao.javaClassReload.utils.Utils.ReturnType;
//
/// **
// *
// * @author Andy Clement
// * @since 0.5.0
// */
// class MethodCopier extends MethodVisitor implements Opcodes {
//
// private boolean isInterface;
//
// private String descriptor;
//
// private TypeDescriptor typeDescriptor;
//
// private String classname;
//
// private String suffix;
//
// private boolean hasFieldsRequiringAccessors;
//
// public MethodCopier(MethodVisitor mv, boolean isInterface, String descriptor, TypeDescriptor typeDescriptor,
// String classname,
// String suffix) {
// super(ASM4, mv);
// this.isInterface = isInterface;
// this.descriptor = descriptor;
// this.typeDescriptor = typeDescriptor;
// this.classname = classname;
// this.suffix = suffix;
// this.hasFieldsRequiringAccessors = this.typeDescriptor.getFieldsRequiringAccessors().length != 0;
// }
//
// @Override
// public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
// // Rename 'this' to 'thiz' in executor otherwise Eclipse debugger will fail (static method with 'this')
// if (index == 0 && name.equals("this")) {
// super.visitLocalVariable("thiz", desc, signature, start, end, index);
// }
// else {
// super.visitLocalVariable(name, desc, signature, start, end, index);
// }
// }
//
// private FieldMember findFieldIfRequiresAccessorUsage(String owner, String name) {
// FieldMember[] fms = this.typeDescriptor.getFieldsRequiringAccessors();
// for (FieldMember fm : fms) {
// if (fm.getName().equals(name) && (owner.equals(classname) || isOneOfOurSupertypes(owner))) { // &&
/// fm.getDeclaringTypeName().equals(owner)) {
// // possibly a match - testcase scenario:
// // 'owner=prot/SubThree' - this is what the FIELD instruction is working on
// // 'dfm=prot/Three' - this is the type that declared the field
// // 'classname=prot/SubThree' - this is the type we are currently operating on
//
// // in our other case though (with JDK Proxies)
// // owner=java/lang/reflect/Proxy
// // dfm=java/lang/reflect/Proxy
// // classname=$Proxy6
// // (this is the funky InvocationHandler field called 'h' in Proxy)
// return fm;
// }
// }
// return null;
// }
//
// /**
// * Determine if the supplied type is a supertype of the current type we are modifying. This is used to determine if
// * the owner we have discovered for a field is one of our supertypes (and so, if it is protected, whether it is
// * something that needs redirecting through an accessor).
// *
// * @param type the type which may be one of this types supertypes
// * @return true if it is a supertype
// */
// private boolean isOneOfOurSupertypes(String type) {
// String stypeName = typeDescriptor.getSupertypeName();
// while (stypeName != null) {
// // TODO [bug] should stop at the first one that has a field in it? and check the field is protected, yada yada yada
// if (stypeName.equals(type)) {
// return true;
// }
// stypeName = typeDescriptor.getTypeRegistry().getDescriptorFor(stypeName).getSupertypeName();
// }
// return false;
// }
//
// private TypeDescriptor getType(String type) {
// TypeDescriptor typeDescriptor = this.typeDescriptor.getTypeRegistry().getDescriptorFor(type);
// return typeDescriptor;
// }
//
// @Override
// public void visitFieldInsn(final int opcode, final String owner, final String name, final String desc) {
// if (hasFieldsRequiringAccessors) {
// // Check if this field reference needs redirecting to an accessor
// FieldMember fm = findFieldIfRequiresAccessorUsage(owner, name);
// if (fm != null) {
// switch (opcode) {
// case GETFIELD:
// mv.visitMethodInsn(INVOKEVIRTUAL, classname, Utils.getProtectedFieldGetterName(name), "()"
// + desc);
// return;
// case PUTFIELD:
// mv.visitMethodInsn(INVOKEVIRTUAL, classname, Utils.getProtectedFieldSetterName(name), "("
// + desc + ")V");
// return;
// case GETSTATIC:
// mv.visitMethodInsn(INVOKESTATIC, classname, Utils.getProtectedFieldGetterName(name), "()"
// + desc);
// return;
// case PUTSTATIC:
// mv.visitMethodInsn(INVOKESTATIC, classname, Utils.getProtectedFieldSetterName(name), "(" + desc
// + ")V");
// return;
// }
// }
// }
// super.visitFieldInsn(opcode, owner, name, desc);
// }
//
// @Override
// public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc) {
// // Is it a private method call?
// // TODO r$ check here because we use invokespecial to avoid virtual dispatch on field changes...
// if (opcode == INVOKESPECIAL && name.charAt(0) != '<' && !name.startsWith("r$")) {
// if (owner.equals(classname)) {
// // private method call
// // leaving the invokespecial alone will cause a verify error
// String descriptor = Utils.insertExtraParameter(owner, desc);
// super.visitMethodInsn(INVOKESTATIC, Utils.getExecutorName(classname, suffix), name, descriptor);
// return;
// }
// else {
// // super call
// // TODO Check if this is true: we can just call the catcher directly if there was one, there is no need
// // for a superdispatcher
//
// // Only need to redirect to the superdispatcher if it was a protected method
// TypeDescriptor supertypeDescriptor = getType(owner);
// MethodMember target = supertypeDescriptor.getByNameAndDescriptor(name + desc);
// if (target != null && target.isProtected()) {
// // A null target means that method is not in the supertype, so didn't get a superdispatcher
// super.visitMethodInsn(INVOKESPECIAL, classname, name + methodSuffixSuperDispatcher, desc);
// }
// else {
// super.visitMethodInsn(opcode, owner, name, desc);
// }
// return;
// }
// }
// // Might be a private static method
// boolean done = false;
// if (opcode == INVOKESTATIC) {
// MethodMember mm = typeDescriptor.getByDescriptor(name, desc);
// if (mm != null && mm.isPrivate()) {
// super.visitMethodInsn(INVOKESTATIC, Utils.getExecutorName(classname, suffix), name, desc);
// done = true;
// }
// }
// if (!done) {
// super.visitMethodInsn(opcode, owner, name, desc);
// }
// }
//
// @Override
// public void visitEnd() {
// if (isInterface) {
// // Create 'dummy methods' for an interface implementation
// createDummyMethodBody();
// super.visitEnd();
// }
// }
//
// private void createDummyMethodBody() {
// ReturnType returnType = Utils.getReturnTypeDescriptor(descriptor);
// int descriptorSize = Utils.getSize(descriptor);
// if (returnType.isVoid()) {
// super.visitInsn(RETURN);
// super.visitMaxs(1, descriptorSize);
// }
// else if (returnType.isPrimitive()) {
// super.visitLdcInsn(0);
// switch (returnType.descriptor.charAt(0)) {
// case 'B':
// case 'C':
// case 'I':
// case 'S':
// case 'Z':
// super.visitInsn(IRETURN);
// super.visitMaxs(2, descriptorSize);
// break;
// case 'D':
// super.visitInsn(DRETURN);
// super.visitMaxs(3, descriptorSize);
// break;
// case 'F':
// super.visitInsn(FRETURN);
// super.visitMaxs(2, descriptorSize);
// break;
// case 'J':
// super.visitInsn(LRETURN);
// super.visitMaxs(3, descriptorSize);
// break;
// default:
// throw new IllegalStateException(returnType.descriptor);
// }
// }
// else {
// // reference type
// super.visitInsn(ACONST_NULL);
// super.visitInsn(ARETURN);
// super.visitMaxs(1, descriptorSize);
// }
// }
// }
